use std::fs::File;
// use std::io::ErrorKind;

use std::io::{self, Read};

fn main() {
    // let _f = File::open("hello.txt");
    // let _f = match _f {
    //     Ok(file) => file,
    //     Err(error) => match error.kind() {
    //         ErrorKind::NotFound => match File::create("hello.txt") {
    //             Ok(fc) => fc,
    //             Err(e) => panic!("Problem creating the file: {:?}", e),
    //         },
    //         other_error => {
    //             panic!("Problem opening the file: {:?}", other_error)
    //         }
    //     }
    // };

    // let _f = File::open("hello.txt").unwrap_or_else(|error| {
    //     if error.kind() == ErrorKind::NotFound {
    //         File::create("hello.txt").unwrap_or_else(|error| {
    //             panic!("Problem creating the file: {:?}", error);
    //         })
    //     } else {
    //         panic!("Problem opening the file: {:?}", error);
    //     }
    // });

    // let _f = File::open("hello.txt").unwrap();
    // let _f = File::open("hello.txt").expect("Failed to open hello.txt");

    let s = read_username_from_file();
    match s {
        Ok(content) => println!("{content}"),
        Err(msg) => println!("read error: {msg}"),
    };
}


// 当 ? 运算符调用 from 函数时，收到的错误类型被转换为由当前函数返回类型所指定的错误类型。
// 这在当函数返回单个错误类型来代表所有可能失败的方式时很有用，即使其可能会因很多种原因失败。
// 只要每一个错误类型都实现了 from 函数来定义如何将自身转换为返回的错误类型，? 运算符会自动处理这些转换。

// 注意你可以在返回 Result 的函数中对 Result 使用 ? 运算符，
// 可以在返回 Option 的函数中对 Option 使用 ? 运算符，
// 但是不可以混合搭配。? 运算符不会自动将 Result 转化为 Option，反之亦然；
// 在这些情况下，可以使用类似 Result 的 ok 方法或者 Option 的 ok_or 方法来显式转换。
fn read_username_from_file() -> Result<String, io::Error> {
    let mut s = String::new();
    // ? 运算符只能被用于返回值与 ? 作用的值相兼容的函数。
    // 因为 ? 运算符被定义为从函数中提早返回一个值，这与示例 9-6 中的 match 表达式有着完全相同的工作方式。

    //只能在返回 Result 或者其它实现了 FromResidual 的类型的函数中使用 ? 运算符。
    let mut f = File::open("src/main.rs")?.read_to_string(&mut s)?;
    Ok(s)
}
